/*============================================================================

  Copyright (c) 2012 Qualcomm Technologies, Inc. All Rights Reserved.
  Qualcomm Technologies Proprietary and Confidential.

============================================================================*/
#include <media/msmb_isp.h>
#include "camera_dbg.h"
#include "gamma40.h"
#include "isp_log.h"

#ifdef ENABLE_GAMMA_LOGGING
  #undef ISP_DBG
  #define ISP_DBG LOGE
#endif

#if 0
#undef ISP_DBG
#define ISP_DBG ALOGE
#endif

#undef CDBG_ERROR
#define CDBG_ERROR ALOGE

#define DEFAULT_CONTRAST 5


static const uint8_t ipl_gammaSigmoid0_5[256] = {
  0,  11,  16,  20,  23,  25,  28,  30,  32,  34,
 36,  37,  39,  41,  42,  44,  45,  47,  48,  49,
 50,  52,  53,  54,  55,  56,  58,  59,  60,  61,
 62,  63,  64,  65,  66,  67,  68,  69,  70,  71,
 71,  72,  73,  74,  75,  76,  77,  77,  78,  79,
 80,  81,  81,  82,  83,  84,  84,  85,  86,  87,
 87,  88,  89,  90,  90,  91,  92,  92,  93,  94,
 94,  95,  96,  96,  97,  98,  98,  99, 100, 100,
101, 102, 102, 103, 103, 104, 105, 105, 106, 107,
107, 108, 108, 109, 109, 110, 111, 111, 112, 112,
113, 113, 114, 115, 115, 116, 116, 117, 117, 118,
118, 119, 119, 120, 121, 121, 122, 122, 123, 123,
124, 124, 125, 125, 126, 126, 127, 127, 128, 128,
129, 129, 130, 130, 131, 131, 132, 132, 133, 133,
134, 134, 135, 136, 136, 137, 137, 138, 138, 139,
139, 140, 140, 141, 142, 142, 143, 143, 144, 144,
145, 146, 146, 147, 147, 148, 148, 149, 150, 150,
151, 152, 152, 153, 153, 154, 155, 155, 156, 157,
157, 158, 159, 159, 160, 161, 161, 162, 163, 163,
164, 165, 165, 166, 167, 168, 168, 169, 170, 171,
171, 172, 173, 174, 174, 175, 176, 177, 178, 178,
179, 180, 181, 182, 183, 184, 184, 185, 186, 187,
188, 189, 190, 191, 192, 193, 194, 195, 196, 197,
199, 200, 201, 202, 203, 205, 206, 207, 208, 210,
211, 213, 214, 216, 218, 219, 221, 223, 225, 227,
230, 232, 235, 239, 244, 255
};

static const uint8_t ipl_gammaSigmoid0_6[256] = {
  0,   7,  11,  13,  16,  18,  20,  22,  24,  26,
 28,  29,  31,  32,  34,  35,  37,  38,  39,  41,
 42,  43,  44,  46,  47,  48,  49,  50,  51,  52,
 54,  55,  56,  57,  58,  59,  60,  61,  62,  63,
 64,  65,  65,  66,  67,  68,  69,  70,  71,  72,
 73,  74,  74,  75,  76,  77,  78,  79,  79,  80,
 81,  82,  83,  84,  84,  85,  86,  87,  87,  88,
 89,  90,  90,  91,  92,  93,  93,  94,  95,  96,
 96,  97,  98,  99,  99, 100, 101, 101, 102, 103,
103, 104, 105, 106, 106, 107, 108, 108, 109, 110,
110, 111, 112, 112, 113, 113, 114, 115, 115, 116,
117, 117, 118, 119, 119, 120, 120, 121, 122, 122,
123, 124, 124, 125, 125, 126, 127, 127, 128, 128,
129, 130, 130, 131, 131, 132, 133, 133, 134, 135,
135, 136, 136, 137, 138, 138, 139, 140, 140, 141,
142, 142, 143, 143, 144, 145, 145, 146, 147, 147,
148, 149, 149, 150, 151, 152, 152, 153, 154, 154,
155, 156, 156, 157, 158, 159, 159, 160, 161, 162,
162, 163, 164, 165, 165, 166, 167, 168, 168, 169,
170, 171, 171, 172, 173, 174, 175, 176, 176, 177,
178, 179, 180, 181, 181, 182, 183, 184, 185, 186,
187, 188, 189, 190, 190, 191, 192, 193, 194, 195,
196, 197, 198, 199, 200, 201, 203, 204, 205, 206,
207, 208, 209, 211, 212, 213, 214, 216, 217, 218,
220, 221, 223, 224, 226, 227, 229, 231, 233, 235,
237, 239, 242, 244, 248, 255
};

static const uint8_t ipl_gammaSigmoid0_7[256] = {
  0,   4,   7,   9,  11,  13,  15,  17,  18,  20,
 21,  23,  24,  26,  27,  29,  30,  31,  32,  34,
 35,  36,  37,  38,  40,  41,  42,  43,  44,  45,
 46,  47,  48,  50,  51,  52,  53,  54,  55,  56,
 57,  58,  59,  60,  61,  62,  62,  63,  64,  65,
 66,  67,  68,  69,  70,  71,  72,  73,  73,  74,
 75,  76,  77,  78,  79,  80,  80,  81,  82,  83,
 84,  85,  85,  86,  87,  88,  89,  90,  90,  91,
 92,  93,  94,  94,  95,  96,  97,  98,  98,  99,
100, 101, 101, 102, 103, 104, 105, 105, 106, 107,
108, 108, 109, 110, 111, 111, 112, 113, 114, 114,
115, 116, 116, 117, 118, 119, 119, 120, 121, 121,
122, 123, 124, 124, 125, 126, 126, 127, 128, 129,
129, 130, 131, 131, 132, 133, 134, 134, 135, 136,
136, 137, 138, 139, 139, 140, 141, 141, 142, 143,
144, 144, 145, 146, 147, 147, 148, 149, 150, 150,
151, 152, 153, 154, 154, 155, 156, 157, 157, 158,
159, 160, 161, 161, 162, 163, 164, 165, 165, 166,
167, 168, 169, 170, 170, 171, 172, 173, 174, 175,
175, 176, 177, 178, 179, 180, 181, 182, 182, 183,
184, 185, 186, 187, 188, 189, 190, 191, 192, 193,
193, 194, 195, 196, 197, 198, 199, 200, 201, 202,
203, 204, 205, 207, 208, 209, 210, 211, 212, 213,
214, 215, 217, 218, 219, 220, 221, 223, 224, 225,
226, 228, 229, 231, 232, 234, 235, 237, 238, 240,
242, 244, 246, 248, 251, 255
};

static const uint8_t ipl_gammaSigmoid0_8[256] = {
  0,   3,   5,   6,   8,  10,  11,  13,  14,  15,
 17,  18,  19,  21,  22,  23,  24,  25,  27,  28,
 29,  30,  31,  32,  34,  35,  36,  37,  38,  39,
 40,  41,  42,  43,  44,  45,  46,  47,  48,  49,
 50,  51,  52,  53,  54,  55,  56,  57,  58,  59,
 60,  61,  62,  63,  64,  65,  66,  67,  68,  69,
 70,  71,  72,  73,  73,  74,  75,  76,  77,  78,
 79,  80,  81,  82,  83,  83,  84,  85,  86,  87,
 88,  89,  90,  90,  91,  92,  93,  94,  95,  96,
 96,  97,  98,  99, 100, 101, 102, 102, 103, 104,
105, 106, 107, 107, 108, 109, 110, 111, 112, 112,
113, 114, 115, 116, 117, 117, 118, 119, 120, 121,
121, 122, 123, 124, 125, 125, 126, 127, 128, 129,
130, 130, 131, 132, 133, 134, 134, 135, 136, 137,
138, 138, 139, 140, 141, 142, 143, 143, 144, 145,
146, 147, 148, 148, 149, 150, 151, 152, 153, 153,
154, 155, 156, 157, 158, 159, 159, 160, 161, 162,
163, 164, 165, 165, 166, 167, 168, 169, 170, 171,
172, 172, 173, 174, 175, 176, 177, 178, 179, 180,
181, 182, 182, 183, 184, 185, 186, 187, 188, 189,
190, 191, 192, 193, 194, 195, 196, 197, 198, 199,
200, 201, 202, 203, 204, 205, 206, 207, 208, 209,
210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
220, 221, 223, 224, 225, 226, 227, 228, 230, 231,
232, 233, 234, 236, 237, 238, 240, 241, 242, 244,
245, 247, 249, 250, 252, 255
};

static const uint8_t ipl_gammaSigmoid0_9[256] = {
  0,   2,   3,   4,   6,   7,   8,   9,  11,  12,
 13,  14,  15,  16,  17,  19,  20,  21,  22,  23,
 24,  25,  26,  27,  28,  29,  30,  32,  33,  34,
 35,  36,  37,  38,  39,  40,  41,  42,  43,  44,
 45,  46,  47,  48,  49,  50,  51,  52,  53,  54,
 55,  56,  57,  58,  59,  60,  61,  62,  63,  64,
 65,  66,  67,  68,  69,  70,  70,  71,  72,  73,
 74,  75,  76,  77,  78,  79,  80,  81,  82,  83,
 84,  85,  86,  87,  88,  89,  89,  90,  91,  92,
 93,  94,  95,  96,  97,  98,  99, 100, 101, 102,
102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
112, 113, 113, 114, 115, 116, 117, 118, 119, 120,
121, 122, 123, 123, 124, 125, 126, 127, 128, 129,
130, 131, 132, 132, 133, 134, 135, 136, 137, 138,
139, 140, 141, 142, 142, 143, 144, 145, 146, 147,
148, 149, 150, 151, 152, 153, 153, 154, 155, 156,
157, 158, 159, 160, 161, 162, 163, 164, 165, 166,
166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
176, 177, 178, 179, 180, 181, 182, 183, 184, 185,
185, 186, 187, 188, 189, 190, 191, 192, 193, 194,
195, 196, 197, 198, 199, 200, 201, 202, 203, 204,
205, 206, 207, 208, 209, 210, 211, 212, 213, 214,
215, 216, 217, 218, 219, 220, 221, 222, 223, 225,
226, 227, 228, 229, 230, 231, 232, 233, 234, 235,
236, 238, 239, 240, 241, 242, 243, 244, 246, 247,
248, 249, 251, 252, 253, 255
};


static const uint8_t ipl_gammaSigmoid1_0[256] = {
  0,   1,   2,   3,   4,   5,   6,   7,   8,   9,
 10,  11,  12,  13,  14,  15,  16,  17,  18,  19,
 20,  21,  22,  23,  24,  25,  26,  27,  28,  29,
 30,  31,  32,  33,  34,  35,  36,  37,  38,  39,
 40,  41,  42,  43,  44,  45,  46,  47,  48,  49,
 50,  51,  52,  53,  54,  55,  56,  57,  58,  59,
 60,  61,  62,  63,  64,  65,  66,  67,  68,  69,
 70,  71,  72,  73,  74,  75,  76,  77,  78,  79,
 80,  81,  82,  83,  84,  85,  86,  87,  88,  89,
 90,  91,  92,  93,  94,  95,  96,  97,  98,  99,
100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
120, 121, 122, 123, 124, 125, 126, 127, 128, 129,
130, 131, 132, 133, 134, 135, 136, 137, 138, 139,
140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
160, 161, 162, 163, 164, 165, 166, 167, 168, 169,
170, 171, 172, 173, 174, 175, 176, 177, 178, 179,
180, 181, 182, 183, 184, 185, 186, 187, 188, 189,
190, 191, 192, 193, 194, 195, 196, 197, 198, 199,
200, 201, 202, 203, 204, 205, 206, 207, 208, 209,
210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
220, 221, 222, 223, 224, 225, 226, 227, 228, 229,
230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
240, 241, 242, 243, 244, 245, 246, 247, 248, 249,
250, 251, 252, 253, 254, 255
};


static const uint8_t ipl_gammaSigmoid1_2[256] = {
  0,   0,   1,   1,   2,   3,   3,   4,   5,   5,
  6,   7,   7,   8,   9,  10,  11,  11,  12,  13,
 14,  15,  15,  16,  17,  18,  19,  20,  21,  22,
 22,  23,  24,  25,  26,  27,  28,  29,  30,  31,
 32,  33,  34,  35,  36,  37,  38,  38,  39,  40,
 41,  42,  43,  44,  45,  46,  48,  49,  50,  51,
 52,  53,  54,  55,  56,  57,  58,  59,  60,  61,
 62,  63,  64,  65,  66,  67,  69,  70,  71,  72,
 73,  74,  75,  76,  77,  78,  79,  81,  82,  83,
 84,  85,  86,  87,  88,  90,  91,  92,  93,  94,
 95,  96,  98,  99, 100, 101, 102, 103, 104, 106,
107, 108, 109, 110, 111, 113, 114, 115, 116, 117,
119, 120, 121, 122, 123, 125, 126, 127, 128, 129,
130, 132, 133, 134, 135, 136, 138, 139, 140, 141,
142, 144, 145, 146, 147, 148, 149, 151, 152, 153,
154, 155, 156, 157, 159, 160, 161, 162, 163, 164,
165, 167, 168, 169, 170, 171, 172, 173, 174, 176,
177, 178, 179, 180, 181, 182, 183, 184, 185, 186,
188, 189, 190, 191, 192, 193, 194, 195, 196, 197,
198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
209, 210, 211, 212, 213, 214, 215, 216, 217, 217,
218, 219, 220, 221, 222, 223, 224, 225, 226, 227,
228, 229, 230, 231, 232, 233, 233, 234, 235, 236,
237, 238, 239, 240, 240, 241, 242, 243, 244, 244,
245, 246, 247, 248, 248, 249, 250, 250, 251, 252,
252, 253, 254, 254, 255, 255
};


static const uint8_t ipl_gammaSigmoid1_5[256] = {
  0,   0,   0,   0,   1,   1,   1,   2,   2,   2,
  3,   3,   4,   4,   5,   5,   6,   6,   7,   7,
  8,   9,   9,  10,  10,  11,  12,  12,  13,  14,
 15,  15,  16,  17,  18,  18,  19,  20,  21,  22,
 22,  23,  24,  25,  26,  27,  28,  29,  29,  30,
 31,  32,  33,  34,  35,  36,  37,  38,  39,  40,
 41,  42,  43,  44,  45,  46,  47,  49,  50,  51,
 52,  53,  54,  55,  56,  58,  59,  60,  61,  62,
 63,  65,  66,  67,  68,  69,  71,  72,  73,  74,
 76,  77,  78,  79,  81,  82,  83,  85,  86,  87,
 89,  90,  91,  93,  94,  95,  97,  98,  99, 101,
102, 104, 105, 106, 108, 109, 111, 112, 114, 115,
116, 118, 119, 121, 122, 124, 125, 127, 128, 130,
131, 133, 134, 136, 137, 139, 140, 141, 143, 144,
146, 147, 149, 150, 151, 153, 154, 156, 157, 158,
160, 161, 162, 164, 165, 166, 168, 169, 170, 172,
173, 174, 176, 177, 178, 179, 181, 182, 183, 184,
186, 187, 188, 189, 190, 192, 193, 194, 195, 196,
197, 199, 200, 201, 202, 203, 204, 205, 206, 208,
209, 210, 211, 212, 213, 214, 215, 216, 217, 218,
219, 220, 221, 222, 223, 224, 225, 226, 226, 227,
228, 229, 230, 231, 232, 233, 233, 234, 235, 236,
237, 237, 238, 239, 240, 240, 241, 242, 243, 243,
244, 245, 245, 246, 246, 247, 248, 248, 249, 249,
250, 250, 251, 251, 252, 252, 253, 253, 253, 254,
254, 254, 255, 255, 255, 255
};


static const uint8_t ipl_gammaSigmoid1_8[256] = {
  0,   0,   0,   0,   0,   0,   1,   1,   1,   1,
  1,   2,   2,   2,   2,   3,   3,   3,   4,   4,
  5,   5,   5,   6,   6,   7,   7,   8,   8,   9,
  9,  10,  11,  11,  12,  12,  13,  14,  14,  15,
 16,  17,  17,  18,  19,  20,  20,  21,  22,  23,
 24,  25,  25,  26,  27,  28,  29,  30,  31,  32,
 33,  34,  35,  36,  37,  38,  39,  40,  41,  42,
 43,  44,  46,  47,  48,  49,  50,  51,  53,  54,
 55,  56,  58,  59,  60,  61,  63,  64,  65,  67,
 68,  69,  71,  72,  74,  75,  77,  78,  79,  81,
 82,  84,  85,  87,  88,  90,  91,  93,  95,  96,
 98,  99, 101, 103, 104, 106, 108, 109, 111, 113,
114, 116, 118, 120, 121, 123, 125, 127, 128, 130,
132, 134, 135, 137, 139, 141, 142, 144, 146, 147,
149, 151, 152, 154, 156, 157, 159, 160, 162, 164,
165, 167, 168, 170, 171, 173, 174, 176, 177, 178,
180, 181, 183, 184, 186, 187, 188, 190, 191, 192,
194, 195, 196, 197, 199, 200, 201, 202, 204, 205,
206, 207, 208, 209, 211, 212, 213, 214, 215, 216,
217, 218, 219, 220, 221, 222, 223, 224, 225, 226,
227, 228, 229, 230, 230, 231, 232, 233, 234, 235,
235, 236, 237, 238, 238, 239, 240, 241, 241, 242,
243, 243, 244, 244, 245, 246, 246, 247, 247, 248,
248, 249, 249, 250, 250, 250, 251, 251, 252, 252,
252, 253, 253, 253, 253, 254, 254, 254, 254, 254,
255, 255, 255, 255, 255, 255
};


static const uint8_t ipl_gammaSigmoid2_1[256] = {
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
  1,   1,   1,   1,   1,   1,   2,   2,   2,   2,
  3,   3,   3,   3,   4,   4,   5,   5,   5,   6,
  6,   7,   7,   7,   8,   8,   9,   9,  10,  11,
 11,  12,  12,  13,  14,  14,  15,  16,  16,  17,
 18,  19,  19,  20,  21,  22,  23,  24,  24,  25,
 26,  27,  28,  29,  30,  31,  32,  33,  34,  35,
 36,  37,  38,  40,  41,  42,  43,  44,  45,  47,
 48,  49,  50,  52,  53,  54,  56,  57,  59,  60,
 61,  63,  64,  66,  67,  69,  70,  72,  73,  75,
 77,  78,  80,  81,  83,  85,  87,  88,  90,  92,
 94,  95,  97,  99, 101, 103, 105, 106, 108, 110,
112, 114, 116, 118, 120, 122, 124, 126, 129, 131,
133, 135, 137, 139, 141, 143, 145, 147, 149, 150,
152, 154, 156, 158, 160, 161, 163, 165, 167, 168,
170, 172, 174, 175, 177, 178, 180, 182, 183, 185,
186, 188, 189, 191, 192, 194, 195, 196, 198, 199,
201, 202, 203, 205, 206, 207, 208, 210, 211, 212,
213, 214, 215, 217, 218, 219, 220, 221, 222, 223,
224, 225, 226, 227, 228, 229, 230, 231, 231, 232,
233, 234, 235, 236, 236, 237, 238, 239, 239, 240,
241, 241, 242, 243, 243, 244, 244, 245, 246, 246,
247, 247, 248, 248, 248, 249, 249, 250, 250, 250,
251, 251, 252, 252, 252, 252, 253, 253, 253, 253,
254, 254, 254, 254, 254, 254, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255
};


static const uint8_t ipl_gammaSigmoid2_4[256] = {
  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
  0,   0,   0,   1,   1,   1,   1,   1,   1,   1,
  1,   2,   2,   2,   2,   3,   3,   3,   3,   4,
  4,   4,   5,   5,   5,   6,   6,   7,   7,   7,
  8,   8,   9,   9,  10,  10,  11,  12,  12,  13,
 13,  14,  15,  16,  16,  17,  18,  18,  19,  20,
 21,  22,  23,  23,  24,  25,  26,  27,  28,  29,
 30,  31,  32,  33,  35,  36,  37,  38,  39,  40,
 42,  43,  44,  46,  47,  48,  50,  51,  52,  54,
 55,  57,  58,  60,  61,  63,  65,  66,  68,  69,
 71,  73,  75,  76,  78,  80,  82,  84,  86,  88,
 89,  91,  93,  95,  97, 100, 102, 104, 106, 108,
110, 112, 115, 117, 119, 122, 124, 126, 129, 131,
133, 136, 138, 140, 143, 145, 147, 149, 151, 153,
155, 158, 160, 162, 164, 166, 167, 169, 171, 173,
175, 177, 179, 180, 182, 184, 186, 187, 189, 190,
192, 194, 195, 197, 198, 200, 201, 203, 204, 205,
207, 208, 209, 211, 212, 213, 215, 216, 217, 218,
219, 220, 222, 223, 224, 225, 226, 227, 228, 229,
230, 231, 232, 232, 233, 234, 235, 236, 237, 237,
238, 239, 239, 240, 241, 242, 242, 243, 243, 244,
245, 245, 246, 246, 247, 247, 248, 248, 248, 249,
249, 250, 250, 250, 251, 251, 251, 252, 252, 252,
252, 253, 253, 253, 253, 254, 254, 254, 254, 254,
254, 254, 254, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255
};

static const uint8_t VFE_Whiteboard_GammaTable[1024] = {
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 4, 4, 5, 5,
  6, 6, 7, 7, 8, 8, 9, 9, 10, 11, 11, 12, 12, 13, 13, 14,
  14, 15, 16, 16, 17, 18, 19, 20, 20, 21, 22, 22, 23, 24, 24, 25,
  26, 27, 28, 28, 29, 30, 31, 32, 33, 34, 35, 35, 36, 37, 38, 39,
  40, 41, 42, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 53, 54, 55,
  56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 68, 69, 70, 71, 72,
  73, 74, 76, 77, 78, 79, 80, 81, 83, 84, 85, 86, 88, 89, 90, 91,
  92, 94, 95, 96, 97, 98, 100, 101, 102, 103, 104, 106, 107, 108, 109, 110,
  112, 113, 114, 115, 116, 117, 118, 119, 121, 122, 123, 124, 125, 126, 127,
  128,
  130, 131, 132, 133, 134, 135, 136, 137, 139, 140, 141, 142, 143, 144, 145,
  146,
  147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161,
  162,
  163, 164, 165, 166, 166, 167, 168, 169, 170, 171, 172, 173, 174, 174, 175,
  176,
  177, 178, 179, 179, 180, 181, 182, 183, 183, 184, 185, 185, 186, 187, 187,
  188,
  189, 190, 190, 191, 192, 192, 193, 194, 194, 195, 196, 196, 197, 198, 198,
  199,
  200, 201, 201, 202, 202, 203, 203, 204, 205, 205, 206, 207, 207, 207, 208,
  209,
  209, 209, 210, 210, 210, 211, 212, 212, 212, 213, 214, 214, 215, 215, 216,
  216,
  216, 217, 217, 218, 218, 219, 219, 220, 220, 221, 221, 221, 222, 222, 222,
  223,
  223, 224, 224, 224, 225, 225, 225, 226, 226, 227, 227, 227, 228, 228, 228,
  229,
  229, 230, 230, 230, 231, 231, 231, 231, 232, 232, 232, 233, 233, 234, 234,
  234,
  235, 235, 235, 235, 235, 236, 236, 236, 236, 237, 237, 237, 237, 238, 238,
  238,
  239, 239, 239, 240, 240, 240, 241, 241, 241, 241, 242, 242, 242, 242, 242,
  243,
  243, 243, 243, 244, 244, 244, 244, 244, 245, 245, 245, 245, 245, 246, 246,
  246,
  246, 246, 246, 246, 246, 246, 247, 247, 247, 247, 247, 248, 248, 248, 248,
  248,
  249, 249, 249, 249, 249, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250,
  251,
  251, 251, 251, 251, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 253,
  253,
  253, 253, 253, 253, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
};

static const uint8_t VFE_Posterization_GammaTable[1024] = {
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 85, 85, 85, 85,
  85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
  85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
  85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
  85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
  85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
  85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
  85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
  85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
  85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
  85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
  85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 170, 170, 170, 170, 170,
  170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170,
  170,
  170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170,
  170,
  170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170,
  170,
  170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170,
  170,
  170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170,
  170,
  170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170,
  170,
  170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170,
  170,
  170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170,
  170,
  170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170,
  170,
  170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170,
  170,
  170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170,
  170,
  170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170,
  170,
  170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170,
  170,
  170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170,
  170,
  170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170,
  170,
  170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170,
  170,
  170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170,
  170,
  170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170,
  170,
  170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170,
  170,
  170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170,
  170,
  170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170,
  170,
  170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170,
  170,
  170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
  255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
  255,
};

static const uint8_t VFE_Blackboard_GammaTable[1024] = {
  /* Gamma table */
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,
  4, 4, 4, 4, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 8, 8,
  8, 9, 9, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, 12, 13, 13,
  13, 14, 14, 14, 15, 15, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19,
  19, 20, 20, 20, 21, 21, 22, 22, 22, 23, 23, 23, 24, 24, 24, 24,
  25, 25, 26, 26, 26, 27, 27, 28, 28, 28, 29, 29, 30, 30, 30, 31,
  31, 32, 32, 32, 33, 33, 33, 34, 34, 35, 35, 36, 36, 37, 37, 38,
  38, 39, 39, 39, 40, 40, 40, 41, 41, 42, 42, 42, 43, 43, 43, 44,
  44, 45, 45, 46, 46, 47, 47, 47, 48, 48, 48, 49, 49, 49, 50, 50,
  51, 51, 52, 52, 53, 53, 53, 54, 54, 54, 55, 55, 56, 56, 57, 57,
  58, 58, 58, 59, 59, 60, 60, 61, 61, 61, 62, 62, 63, 63, 63, 64,
  64, 65, 65, 66, 66, 66, 67, 67, 67, 68, 68, 69, 69, 69, 70, 70,
  71, 71, 71, 72, 72, 73, 73, 74, 74, 74, 75, 75, 76, 76, 77, 77,
  77, 78, 78, 79, 79, 79, 80, 80, 80, 81, 81, 81, 82, 82, 83, 83,
  83, 84, 84, 85, 85, 86, 86, 86, 87, 87, 87, 88, 88, 89, 89, 89,
  90, 90, 90, 91, 91, 92, 92, 92, 93, 93, 93, 94, 94, 95, 95, 95,
  96, 96, 96, 97, 97, 98, 98, 99, 99, 100, 100, 100, 101, 101, 101, 102,
  102, 102, 103, 103, 103, 104, 104, 104, 105, 105, 106, 106, 106, 107, 107,
  107,
  108, 108, 108, 109, 109, 110, 110, 111, 111, 111, 112, 112, 112, 113, 113,
  113,
  114, 114, 115, 115, 115, 116, 116, 116, 117, 117, 117, 118, 118, 118, 119,
  119,
  119, 120, 120, 120, 121, 121, 121, 122, 122, 122, 123, 123, 123, 124, 124,
  124,
  125, 125, 125, 126, 126, 126, 127, 127, 127, 128, 128, 128, 129, 129, 129,
  130,
  130, 130, 131, 131, 131, 132, 132, 132, 133, 133, 134, 134, 134, 135, 135,
  135,
  136, 136, 136, 136, 137, 137, 137, 138, 138, 138, 139, 139, 139, 140, 140,
  140,
  141, 141, 141, 141, 142, 142, 142, 143, 143, 143, 143, 144, 144, 145, 145,
  145,
  145, 146, 146, 147, 147, 147, 147, 148, 148, 148, 149, 149, 149, 149, 150,
  150,
  150, 150, 151, 151, 152, 152, 152, 152, 153, 153, 154, 154, 154, 154, 155,
  155,
  155, 155, 156, 156, 156, 156, 157, 157, 157, 157, 158, 158, 159, 159, 159,
  159,
  160, 160, 160, 161, 161, 161, 161, 162, 162, 163, 163, 163, 163, 164, 164,
  164,
  164, 165, 165, 165, 165, 165, 166, 166, 166, 166, 167, 167, 167, 168, 168,
  168,
  168, 169, 169, 170, 170, 170, 170, 171, 171, 171, 172, 172, 172, 172, 173,
  173,
  173, 173, 173, 174, 174, 174, 174, 174, 175, 175, 175, 175, 176, 176, 176,
  177,
  177, 177, 177, 178, 178, 178, 179, 179, 179, 179, 180, 180, 180, 181, 181,
  181,
  181, 182, 182, 182, 182, 183, 183, 183, 183, 184, 184, 184, 184, 184, 185,
  185,
  185, 185, 185, 185, 186, 186, 186, 186, 187, 187, 187, 188, 188, 188, 188,
  189,
  189, 189, 189, 190, 190, 190, 190, 191, 191, 191, 191, 192, 192, 192, 192,
  193,
  193, 193, 193, 194, 194, 194, 194, 195, 195, 195, 195, 196, 196, 196, 196,
  197,
  197, 197, 197, 197, 197, 198, 198, 198, 198, 198, 198, 198, 199, 199, 199,
  199,
  200, 200, 200, 200, 201, 201, 201, 201, 202, 202, 202, 202, 202, 203, 203,
  203,
  203, 204, 204, 204, 204, 205, 205, 205, 205, 206, 206, 206, 206, 206, 207,
  207,
  207, 207, 208, 208, 208, 208, 208, 209, 209, 209, 209, 210, 210, 210, 210,
  210,
  210, 210, 211, 211, 211, 211, 211, 211, 211, 211, 212, 212, 212, 212, 213,
  213,
  213, 213, 213, 214, 214, 214, 214, 215, 215, 215, 215, 215, 215, 216, 216,
  216,
  216, 217, 217, 217, 217, 217, 218, 218, 218, 218, 219, 219, 219, 219, 219,
  219,
  220, 220, 220, 220, 221, 221, 221, 221, 221, 221, 222, 222, 222, 222, 223,
  223,
  223, 223, 223, 223, 224, 224, 224, 224, 225, 225, 225, 225, 225, 225, 225,
  226,
  226, 226, 226, 227, 227, 227, 227, 227, 227, 227, 227, 228, 228, 228, 228,
  228,
  228, 228, 228, 228, 229, 229, 229, 229, 230, 230, 230, 230, 230, 230, 230,
  231,
  231, 231, 231, 232, 232, 232, 232, 232, 232, 232, 233, 233, 233, 233, 234,
  234,
  234, 234, 234, 234, 234, 235, 235, 235, 235, 236, 236, 236, 236, 236, 236,
  236,
  236, 237, 237, 237, 237, 238, 238, 238, 238, 238, 238, 238, 239, 239, 239,
  239,
  240, 240, 240, 240, 240, 240, 240, 240, 241, 241, 241, 241, 242, 242, 242,
  242,
  242, 242, 242, 242, 243, 243, 243, 243, 244, 244, 244, 244, 244, 244, 244,
  244,
  244, 244, 244, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 246, 246,
  246,
  246, 247, 247, 247, 247, 247, 247, 247, 247, 247, 248, 248, 248, 248, 249,
  249,
  249, 249, 249, 249, 249, 249, 249, 250, 250, 250, 250, 251, 251, 251, 251,
  251,
  251, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 253, 253, 254,
  255,
};

/*  Y Gamma Config Command */


#define PRINT_TABLE(table) ({ \
  int i; \
  ISP_DBG(ISP_MOD_GAMMA, "gamma table from chromatix"); \
  for(i=0; i<MAX_GAMMA_TABLE_SIZE/16; i++) \
    ISP_DBG(ISP_MOD_GAMMA, "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d", \
      table[i], table[i+1], table[i+2], table[i+3], table[i+4], \
      table[i+5], table[i+6], table[i+7], table[i+8], \
      table[i+9], table[i+10], table[i+11], table[i+12], \
      table[i+13], table[i+14], table[i+15]); })

/** gamma_update_tab_on_contrast:
 *    @contrast: contrast to be applied
 *    @ibits: table entry size in bits
 *    @input_table: input table
 *    @output_table: output table
 *
 *  This function updates gamma table depending on contrast
 *
 *  Return: TRUE  - Success
 *          FALSE - Input/Output table is NULL or contrast value is invalid
 **/
static int8_t gamma_update_tab_on_contrast(int contrast, int lut_size,
  isp_gamma_rgb_t *input_table_rgb, isp_gamma_rgb_t *output_table_rgb)
{
  int i;
  int entries;
  const uint8_t * gamma_table;
  entries = (lut_size >= 0) ? lut_size : 256;

  /* Apply Sigmoid Gamma Table */
  if (input_table_rgb == NULL || output_table_rgb == NULL) {
    ISP_DBG(ISP_MOD_GAMMA, "%s: input improper\n", __func__);

    return FALSE;
  }

  ISP_DBG(ISP_MOD_GAMMA, "%s: E, contrast = %d\n", __func__, contrast);
  switch (contrast) {
  case 10:
    gamma_table = ipl_gammaSigmoid2_4;
    break;

  case 9:
    gamma_table = ipl_gammaSigmoid2_1;
    break;

  case 8:
    gamma_table = ipl_gammaSigmoid1_8;
    break;

  case 7:
    gamma_table = ipl_gammaSigmoid1_5;
    break;

  case 6:
    gamma_table = ipl_gammaSigmoid1_2;
    break;
  case 5:
      /* the input and output table are the same */
        *output_table_rgb = *input_table_rgb;
      return TRUE;
  case 4:
    gamma_table = ipl_gammaSigmoid0_9;
    break;

  case 3:
    gamma_table = ipl_gammaSigmoid0_8;
    break;

  case 2:
    gamma_table = ipl_gammaSigmoid0_7;
    break;

  case 1:
    gamma_table = ipl_gammaSigmoid0_6;
    break;

  case 0:
    gamma_table = ipl_gammaSigmoid0_5;
    break;

  default:
    ISP_DBG(ISP_MOD_GAMMA, " %s: invalid contrast\n", __func__);
    return FALSE;
  }

  /* do look up */
  for (i = 0; i < entries; i++) {
    output_table_rgb->gamma_r[i] = gamma_table[input_table_rgb->gamma_r[i]];
    output_table_rgb->gamma_g[i] = gamma_table[input_table_rgb->gamma_g[i]];
    output_table_rgb->gamma_b[i] = gamma_table[input_table_rgb->gamma_b[i]];
  }

  ISP_DBG(ISP_MOD_GAMMA, "%s: success\n", __func__);

  return TRUE;
} /* gamma_update_tab_on_contrast */


/** get_hi_lo_gamma_bits
 *
 *  @table: gamma table
 *  @skipRatio: number of entries to be skipped
 *  @i: index in gamma table
 *
 *    The higher 8 bits in the configuration contains the delta between the
 *    current GammaTable value and the next value, while the lower 8 bits
 *    contains the current GammaTable value
 */
static int16_t get_hi_lo_gamma_bits(uint8_t *table, int skipRatio,
  int i)
{
  int16_t hw_lut_entry;
  uint8_t delta_lut;

  delta_lut = table[skipRatio*(i+1)] - table[skipRatio * i];
  hw_lut_entry = (int16_t)(delta_lut << GAMMA40_HW_PACK_BIT) + table[skipRatio * i];
  return hw_lut_entry;
}

/** get_last_gamma_value
 *
 *  @table: gamma table
 *  @skipRatio: number of entries to be skipped
 *
 */
static int16_t get_last_gamma_value(const uint8_t *table, const int skipRatio)
{
  int16_t hw_lut_entry;
  uint8_t delta_lut;

  /* consider the next entry of the last entry (255) to be 256.
     value 256 suggested by system team */
  uint32_t next_entry_final = 256;

  /* this is effectively  table[63] - table[62];
     this part is the delta */
  /* use 256 as next entry of last entry */
  delta_lut = next_entry_final -
    table[(ISP_GAMMA_NUM_ENTRIES - 1) * skipRatio];
  /* scale the delta */

  /* form the value:  upper byte is delta,
     lower byte is the entry itself. */
  hw_lut_entry = (int16_t)(delta_lut <<  GAMMA40_HW_PACK_BIT) +
    table[skipRatio * (ISP_GAMMA_NUM_ENTRIES - 1)];

  return hw_lut_entry;
}

/** gamma_update_vfe_table:
 *    @gamma_config_cmd: configuration command
 *    @table_rgb: pointer to table
 *    @size: size of the table
 *
 *  This function runs in ISP HW thread context.
 *
 *  This function updates gamma table depending on contrast
 *
 *  Return: TRUE  - Success
 *          FALSE - Input/Output table is NULL or contrast value is invalid
 **/

static void gamma_update_vfe_table(volatile ISP_GammaConfigCmdType *
  gamma_config_cmd, isp_gamma_rgb_t *table_rgb, uint32_t lut_size)
{
  int i;
  uint8_t *table_r = table_rgb->gamma_r;
  uint8_t *table_g = table_rgb->gamma_g;
  uint8_t *table_b = table_rgb->gamma_b;

  /* ratio between number of LUT entries in Tuning data vs number of
     actual VFE gamma LUT entries.
     Decide how do we fill HW LUT from chromatix lut*/
  int skipRatio = lut_size / ISP_GAMMA_NUM_ENTRIES;

  for (i = 0; i < ISP_GAMMA_NUM_ENTRIES - 1; i++) {
    gamma_config_cmd->Gamatbl.hw_table_r[i] = get_hi_lo_gamma_bits(table_r, skipRatio, i);
    gamma_config_cmd->Gamatbl.hw_table_g[i] = get_hi_lo_gamma_bits(table_g, skipRatio, i);
    gamma_config_cmd->Gamatbl.hw_table_b[i] = get_hi_lo_gamma_bits(table_b, skipRatio, i);
  }

  gamma_config_cmd->Gamatbl.hw_table_r[ISP_GAMMA_NUM_ENTRIES - 1] =
    get_last_gamma_value(table_r, skipRatio);
  gamma_config_cmd->Gamatbl.hw_table_g[ISP_GAMMA_NUM_ENTRIES - 1] =
    get_last_gamma_value(table_g, skipRatio);
  gamma_config_cmd->Gamatbl.hw_table_b[ISP_GAMMA_NUM_ENTRIES - 1] =
    get_last_gamma_value(table_b, skipRatio);
} /* gamma_update_vfe_table */

/** set_gamma_table
 *
 *  @p_gamma_rgb: contain pointers to each color of gamma
 *  @gamma: single gamma table
 *
 *  This function runs in ISP HW thread context.
 *
 *  This function initializes rgb gamma pointers
 *
 *  Return: None
 */
static void set_gamma_table(isp_gamma_rgb_t *gamma_rgb,
  uint8_t *gamma)
{
  memcpy(gamma_rgb->gamma_r, gamma, MAX_GAMMA_TABLE_SIZE * sizeof(uint8_t));
  memcpy(gamma_rgb->gamma_g, gamma, MAX_GAMMA_TABLE_SIZE * sizeof(uint8_t));
  memcpy(gamma_rgb->gamma_b, gamma, MAX_GAMMA_TABLE_SIZE * sizeof(uint8_t));
}


/** copy_gamma
 *
 *  @dst: destination
 *  @src: src
 *  @size: size
 *
 *  This function runs in ISP HW thread context.
 *
 *  This function copies rgb gamma table
 *
 *  Return: None
 */
static void copy_gamma(isp_gamma_rgb_t *dst,
  isp_gamma_rgb_t *src, size_t size)
{
  memcpy(dst->gamma_r, src->gamma_r, size);
  memcpy(dst->gamma_g, src->gamma_g, size);
  memcpy(dst->gamma_b, src->gamma_b, size);
}

/**   chromatix_to_isp_gamma
 *
 *  @p_gamma_rgb: isp gamma rgb table
 *  @chromatix_gamma_table: chromoatix gamma table
 *
 *  This function runs in ISP HW thread context.
 *
 *  This function initializes gamma table from chromatix
 *
 *  Return: None
 */
static void chromatix_to_isp_gamma(isp_gamma_rgb_t *gamma_rgb,
  chromatix_gamma_table_type *chromatix_gamma_table)
{
  memcpy(gamma_rgb->gamma_r, chromatix_gamma_table->gamma, GAMMA_TABLE_SIZE * sizeof(uint8_t));
  memcpy(gamma_rgb->gamma_g, chromatix_gamma_table->gamma, GAMMA_TABLE_SIZE * sizeof(uint8_t));
  memcpy(gamma_rgb->gamma_b, chromatix_gamma_table->gamma, GAMMA_TABLE_SIZE * sizeof(uint8_t));
}

/** gamma_interpolate
 *
 *    @tbl1: input table 1
 *    @tbl2: input table 2
 *    @out: out table
 *    @ratio:
 *
 *  Interpolate for each of tree colors RGB
 *  and summurise result in one table
 *
 *  Return: None
 */
static void gamma_interpolate(isp_gamma_rgb_t *tbl1,
    isp_gamma_rgb_t *tbl2, isp_gamma_rgb_t *gamma_rgb,
  float ratio)
{
  int i;

  TBL_INTERPOLATE_INT(tbl1->gamma_r, tbl2->gamma_r, gamma_rgb->gamma_r,
    ratio, MAX_GAMMA_TABLE_SIZE, i);
  TBL_INTERPOLATE_INT(tbl1->gamma_g, tbl2->gamma_g, gamma_rgb->gamma_g,
    ratio, MAX_GAMMA_TABLE_SIZE, i);
  TBL_INTERPOLATE_INT(tbl1->gamma_b, tbl2->gamma_b, gamma_rgb->gamma_b,
    ratio, MAX_GAMMA_TABLE_SIZE, i);
}

/** gamma_trigger_update:
 *    @mod: gamma module instance
 *    @trigger_params: module trigger update params
 *    @in_param_size: enable parameter size
 *
 *  This function runs in ISP HW thread context.
 *
 *  This function checks and initiates triger update of module
 *
 *  Return:   0 - Success
 *           -1 - get aec ratio returned error
 **/
static int gamma_trigger_update(isp_gamma_mod_t *mod,
  isp_pix_trigger_update_input_t *trigger_params, uint32_t in_param_size)
{
  int rc = 0;
  int i;

  trigger_ratio_t trigger_ratio;
  trigger_point_type  *lowlight = NULL, *outdoor = NULL;
  isp_stats_udpate_t *stats_update =
    &trigger_params->trigger_input.stats_update;
  chromatix_parms_type *pchromatix =
    (chromatix_parms_type *)trigger_params->cfg.chromatix_ptrs.chromatixPtr;
  chromatix_gamma_type *pchromatix_gamma =
    &(pchromatix->chromatix_VFE.chromatix_gamma);
  tuning_control_type control_gamma = pchromatix_gamma->control_gamma;
  uint8_t is_burst = IS_BURST_STREAMING((&trigger_params->cfg));
  int backlight_comp_update = FALSE;
  int update_gamma = FALSE;
  isp_gamma_rgb_t contrast_gamma_table_rgb;

  if (!mod->enable) {
    ISP_DBG(ISP_MOD_GAMMA, "%s: gamma not enabled", __func__);

    return 0;
  }

  if (!mod->trigger_enable) {
    ISP_DBG(ISP_MOD_GAMMA, "%s: gamma trigger not enabled", __func__);

    return 0;
  }

  switch(trigger_params->cfg.effects.spl_effect) {
  case CAM_EFFECT_MODE_POSTERIZE:
  case CAM_EFFECT_MODE_SOLARIZE:
  case CAM_EFFECT_MODE_WHITEBOARD:
  case CAM_EFFECT_MODE_BLACKBOARD: {
    ISP_DBG(ISP_MOD_GAMMA, "%s: Special effect %d applied skip trigger",
      __func__, trigger_params->cfg.effects.spl_effect);
    gamma_update_vfe_table(&mod->ISP_GammaCfgCmd, &mod->gamma_table_rgb,
      mod->gamma_lut_size);
    return 0;
  }
    break;

  default:
    break;
  }

  if (!isp_util_aec_check_settled(&trigger_params->trigger_input.stats_update.aec_update)) {
    ISP_DBG(ISP_MOD_GAMMA, "%s: AEC not settled", __func__);
    /* return 0;  TODO remove this after 3a stable */
  }

  lowlight =  &(pchromatix_gamma->gamma_lowlight_trigger);
  outdoor = &(pchromatix_gamma->gamma_outdoor_trigger);

  rc = isp_util_get_aec_ratio2(mod->notify_ops->parent, control_gamma, outdoor,
     lowlight, &(stats_update->aec_update), is_burst, &trigger_ratio);

  backlight_comp_update = mod->enable_backlight_compensation &&
    stats_update->asd_update.backlight_detected &&
    (mod->backlight_severity !=
      stats_update->asd_update.backlight_scene_severity);

  ISP_DBG(ISP_MOD_GAMMA, "%s: bklight %d severity %d", __func__, backlight_comp_update,
     stats_update->asd_update.backlight_scene_severity);

  update_gamma =
    ((trigger_params->cfg.streaming_mode != mod->old_streaming_mode) ||
      !F_EQUAL(trigger_ratio.ratio, mod->gamma_ratio.ratio)) ||
    backlight_comp_update || mod->reload_params||
    (trigger_ratio.lighting != mod->gamma_ratio.lighting);

  ISP_DBG(ISP_MOD_GAMMA, "%s: update %d ratio %f lighting %d", __func__, update_gamma,
     trigger_ratio.ratio, trigger_ratio.lighting);

  if (update_gamma) {

    if (trigger_ratio.lighting == TRIGGER_OUTDOOR)
      gamma_interpolate(&mod->default_gamma_tbl, &mod->outdoor_gamma_tbl,
        &(mod->gamma_table_rgb), trigger_ratio.ratio);
    else if (trigger_ratio.lighting == TRIGGER_LOWLIGHT)
      gamma_interpolate(&mod->default_gamma_tbl, &mod->lowlight_gamma_tbl,
        &(mod->gamma_table_rgb), trigger_ratio.ratio);
    else
      copy_gamma(&(mod->gamma_table_rgb), &mod->default_gamma_tbl,
        MAX_GAMMA_TABLE_SIZE);

    if (backlight_comp_update) {
      float bl_ratio =
        (float)stats_update->asd_update.backlight_scene_severity/255.0;
      ISP_DBG(ISP_MOD_GAMMA, "%s: bl_ratio %f", __func__, bl_ratio);

      bl_ratio = MIN(0, MAX(1.0, bl_ratio));
#if 0
      /* FIXME: there is no backlight gamma in chromatix 301 */
      TBL_INTERPOLATE_INT(pchromatix->backlight_gamma_table.gamma,
        mod->p_gamma_table, mod->p_gamma_table,
        bl_ratio, MAX_GAMMA_TABLE_SIZE, i);
#endif
      mod->backlight_severity =
        stats_update->asd_update.backlight_scene_severity;
    }
    mod->old_streaming_mode = trigger_params->cfg.streaming_mode;
    mod->gamma_ratio = trigger_ratio;
    mod->hw_update_pending = TRUE;
  }

  /* update based on contrast */
  if (trigger_params->cfg.bestshot_mode == CAM_SCENE_MODE_OFF) {
    switch(mod->gamma_table_type) {
      case GAMMA_TABLE_SOLARIZE:
      case GAMMA_TABLE_POSTERIZE:
      case GAMMA_TABLE_WHITE_BOARD:
      case GAMMA_TABLE_BLACK_BOARD:
      case GAMMA_TABLE_BACKLIGHT: {
        ISP_DBG(ISP_MOD_GAMMA, "%s: Dont apply contrast", __func__);
        gamma_update_vfe_table(&mod->ISP_GammaCfgCmd, &mod->gamma_table_rgb,
          mod->gamma_lut_size);
        break;
      }
      default: {
        ISP_DBG(ISP_MOD_GAMMA, "%s: Apply contrast %d trig_update %d", __func__, mod->contrast,
          mod->trigger_update);
        if (mod->contrast != DEFAULT_CONTRAST) {
          gamma_update_tab_on_contrast(mod->contrast,
            mod->gamma_lut_size, &(mod->gamma_table_rgb),
            &contrast_gamma_table_rgb);

          gamma_update_vfe_table(&mod->ISP_GammaCfgCmd, &contrast_gamma_table_rgb,
            mod->gamma_lut_size);
        } else {
          gamma_update_vfe_table(&mod->ISP_GammaCfgCmd, &mod->gamma_table_rgb,
            mod->gamma_lut_size);

        }
      }
    }
  } else {
    gamma_update_vfe_table(&mod->ISP_GammaCfgCmd, &mod->gamma_table_rgb,
      mod->gamma_lut_size);
  }

  ISP_DBG(ISP_MOD_GAMMA, "%s: Update gamma %d status %d, hw_update = %d",
    __func__, update_gamma, rc, mod->hw_update_pending);

  memcpy(&(trigger_params->cfg.gamma_rgb), &(mod->ISP_GammaCfgCmd.Gamatbl),
    sizeof(isp_gamma_t));

  return rc;
} /* isp_gamma_trigger_update */

/** gamma_set_table:
 *    @mod: gamma module instance
 *    @pix_settings: PIX parameters
 *    @gamma_table_type: gamma table type
 *
 *  This function runs in ISP HW thread context.
 *
 *  This function sets gamma table depending on special effect/ bestshot.
 *
 *  Return:   0 - Success
 **/
static int gamma_set_table(isp_gamma_mod_t* mod,
  isp_hw_pix_setting_params_t *pix_settings, isp_gamma_table_t gamma_table_type)
{
   int rc =0;
   chromatix_parms_type *chromatix_ptr =
     (chromatix_parms_type *)pix_settings->chromatix_ptrs.chromatixPtr;
   chromatix_gamma_type *pchromatix_gamma =
     &(chromatix_ptr->chromatix_VFE.chromatix_gamma);

  ISP_DBG(ISP_MOD_GAMMA, "%s: gamma_table_type %d", __func__, gamma_table_type);

  mod->gamma_lut_size = GAMMA40_CHROMATIX_LUT_SIZE;
  switch (gamma_table_type) {
    case GAMMA_TABLE_OUTDOOR:
      chromatix_to_isp_gamma(&(mod->gamma_table_rgb),
        &(pchromatix_gamma->outdoor_gamma_table));
      mod->gamma_ratio.lighting = TRIGGER_OUTDOOR;
      mod->gamma_ratio.ratio = 0.0;
      break;

    case GAMMA_TABLE_LOWLIGHT:
      chromatix_to_isp_gamma(&(mod->gamma_table_rgb),
        &(pchromatix_gamma->lowlight_gamma_table));
      mod->gamma_ratio.lighting = TRIGGER_LOWLIGHT;
      mod->gamma_ratio.ratio = 0.0;
      break;

#if 0
    case GAMMA_TABLE_BACKLIGHT:
      chromatix_to_isp_gamma(&(mod->p_gamma_table_rgb),
        &(pchromatix_gamma->backlight_gamma_table));
      break;
#endif
    case GAMMA_TABLE_SOLARIZE:
      mod->gamma_table_rgb =  mod->solarize_gamma_table;
      break;

    case GAMMA_TABLE_POSTERIZE:
      set_gamma_table(&(mod->gamma_table_rgb),
        (uint8_t *)VFE_Posterization_GammaTable);
      mod->gamma_lut_size = 1024;
      break;

    case GAMMA_TABLE_WHITE_BOARD:
      set_gamma_table(&(mod->gamma_table_rgb),
        (uint8_t *)VFE_Whiteboard_GammaTable);
      mod->gamma_lut_size = 1024;
      break;

    case GAMMA_TABLE_BLACK_BOARD:
      set_gamma_table(&(mod->gamma_table_rgb),
        (uint8_t *)VFE_Blackboard_GammaTable);
      mod->gamma_lut_size = 1024;
      break;

    case GAMMA_TABLE_DEFAULT:
    default:
      chromatix_to_isp_gamma(&(mod->gamma_table_rgb),
        &(pchromatix_gamma->default_gamma_table));
      mod->gamma_ratio.lighting = TRIGGER_NORMAL;
      mod->gamma_ratio.ratio = 1.0;
      break;
  }
  mod->gamma_table_type = gamma_table_type;
  mod->hw_update_pending = TRUE;

  return rc;
} /* vfe_gamma_set_table */

/** gamma_set_bestshot:
 *    @mod: gamma module instance
 *    @pix_settings: PIX parameters
 *    @in_param_size: parameter size
 *
 *  This function runs in ISP HW thread context.
 *
 *  This function configures gamma module according bestshot set.
 *
 *  Return:   0 - Success
 *           -1 - Parameter size mismatch
 **/
static int gamma_set_bestshot(isp_gamma_mod_t* mod,
  isp_hw_pix_setting_params_t *pix_settings, uint32_t in_param_size)
{
  int rc = 0;
  ISP_DBG(ISP_MOD_GAMMA, "%s: mode %d", __func__, pix_settings->bestshot_mode);

  if (in_param_size != sizeof(isp_hw_pix_setting_params_t)) {
    /* size mismatch */
    CDBG_ERROR("%s: size mismatch, expecting = %d, received = %d",
           __func__, sizeof(isp_hw_pix_setting_params_t), in_param_size);

    return -1;
  }

  switch(pix_settings->bestshot_mode) {
  case CAM_SCENE_MODE_LANDSCAPE:
  case CAM_SCENE_MODE_SNOW:
  case CAM_SCENE_MODE_BEACH:
  case CAM_SCENE_MODE_SPORTS:
  case CAM_SCENE_MODE_ACTION:
    rc = gamma_set_table(mod, pix_settings, GAMMA_TABLE_OUTDOOR);
    break;

  case CAM_SCENE_MODE_NIGHT:
  case CAM_SCENE_MODE_FIREWORKS:
  case CAM_SCENE_MODE_NIGHT_PORTRAIT:
    rc = gamma_set_table(mod, pix_settings, GAMMA_TABLE_LOWLIGHT);
    break;

  case CAM_SCENE_MODE_BACKLIGHT:
    rc = gamma_set_table(mod, pix_settings, GAMMA_TABLE_BACKLIGHT);
    break;

  default:
    rc = gamma_set_table(mod, pix_settings, GAMMA_TABLE_DEFAULT);
    break;
  }

  mod->trigger_enable = TRUE;

  if (rc == 0){
    ISP_DBG(ISP_MOD_GAMMA, "%s: enable update through BSM for mode : %d",__func__,
      pix_settings->bestshot_mode);
    mod->hw_update_pending = TRUE;
  }

  return rc;
} /* vfe_gamma_set_bestshot */

/** gamma_set_spl_effect:
 *    @mod: gamma module instance
 *    @pix_settings: PIX parameters
 *    @in_param_size: parameter size
 *
 *  This function runs in ISP HW thread context.
 *
 *  This function configures gamma module according special effect set.
 *
 *  Return:   0 - Success
 *           -1 - Parameter size mismatch
 **/
static int gamma_set_spl_effect(isp_gamma_mod_t* mod,
  isp_hw_pix_setting_params_t *pix_settings, uint32_t in_param_size)
{
  int rc = 0;
  int type;
  chromatix_parms_type *chromatix =
    (chromatix_parms_type *)pix_settings->chromatix_ptrs.chromatixPtr;

  ISP_DBG(ISP_MOD_GAMMA, "%s: E\n",__func__);
  if (in_param_size != sizeof(isp_hw_pix_setting_params_t)) {
    /* size mismatch */
    CDBG_ERROR("%s: size mismatch, expecting = %d, received = %d",
           __func__, sizeof(isp_mod_set_enable_t), in_param_size);

    return -1;
  }

  if (pix_settings->bestshot_mode != CAM_SCENE_MODE_OFF) {
    CDBG_HIGH("%s: Best shot enabled, skip set effect", __func__);

    return 0;
  }

  type = pix_settings->effects.spl_effect;
  ISP_DBG(ISP_MOD_GAMMA, "%s: contrast %d effect type %d", __func__, mod->contrast, type);

  if(mod->contrast != DEFAULT_CONTRAST)
    switch(type) {
    case CAM_EFFECT_MODE_POSTERIZE:
    case CAM_EFFECT_MODE_BLACKBOARD:
    case CAM_EFFECT_MODE_WHITEBOARD:
    case CAM_EFFECT_MODE_SOLARIZE: {
      /* UI should prevent this */
      CDBG_HIGH("%s: Warning Overriding contrast value to default",
        __func__);
      mod->contrast = DEFAULT_CONTRAST;
      /* pix_settings->effects.contrast = DEFAULT_CONTRAST; */
    }
      break;

    default:
      break;
    }

  ISP_DBG(ISP_MOD_GAMMA, "%s: type %d", __func__, type);
  switch (type) {
  case CAM_EFFECT_MODE_POSTERIZE:
   rc = gamma_set_table(mod, pix_settings, GAMMA_TABLE_POSTERIZE);
    break;

  case CAM_EFFECT_MODE_SOLARIZE:
   rc = gamma_set_table(mod, pix_settings, GAMMA_TABLE_SOLARIZE);
    break;

  case CAM_EFFECT_MODE_BLACKBOARD:
   rc = gamma_set_table(mod, pix_settings, GAMMA_TABLE_BLACK_BOARD);
    break;

  case CAM_EFFECT_MODE_WHITEBOARD:
   rc = gamma_set_table(mod, pix_settings, GAMMA_TABLE_WHITE_BOARD);
    break;

  default:
   rc = gamma_set_table(mod, pix_settings, GAMMA_TABLE_DEFAULT);
    break;
  }

  if (rc == 0){
    ISP_DBG(ISP_MOD_GAMMA, "%s: enable update through special effect type %d",__func__, type);
    mod->hw_update_pending = TRUE;
  }

  return rc;
} /* gamma_set_spl_effect */

/** gamma_set_solarize_table:
 *    @mod: gamma module instance
 *    @chromatix_ptr: pointer to chromatix
 *
 *  This function runs in ISP HW thread context.
 *
 *  This function sets solarize table
 *
 *  Return:   None
 **/
static void gamma_set_solarize_table(isp_gamma_mod_t *mod,
  chromatix_parms_type *chromatix_ptr)
{
  /* FIXME: There is no solorize reflection point in chromatix 301 */
  int i;
  uint16_t solarize_reflection_point = 0;
  chromatix_gamma_type *pchromatix_gamma =
    &(chromatix_ptr->chromatix_VFE.chromatix_gamma);
  isp_gamma_rgb_t Gamma_Lut;

  chromatix_to_isp_gamma(&Gamma_Lut, &(pchromatix_gamma->default_gamma_table));

  /* The solarize effect is achieved by inverting the output of the gamma table
     if the input is larger than reflex point. The output remains the same if                                                   .
     the input is less than or equal to the reflex point.
     The recommended reflex point is the midpoint of the input range e.g.
     128 for an 8-bit input */
  while( Gamma_Lut.gamma_r[solarize_reflection_point] <= GAMMA_REFLEX_POINT )
    solarize_reflection_point++;

  copy_gamma(&mod->solarize_gamma_table, &Gamma_Lut, solarize_reflection_point);

  for (i = solarize_reflection_point; i < GAMMA_TABLE_SIZE; i++) {
    mod->solarize_gamma_table.gamma_r[i]  =
      ((255 - Gamma_Lut.gamma_r[i]) * Gamma_Lut.gamma_r[solarize_reflection_point] /
       (255 - Gamma_Lut.gamma_r[solarize_reflection_point]));

    mod->solarize_gamma_table.gamma_g[i] =
      ((255 - Gamma_Lut.gamma_g[i]) * Gamma_Lut.gamma_g[solarize_reflection_point] /
       (255 - Gamma_Lut.gamma_g[solarize_reflection_point]));

    mod->solarize_gamma_table.gamma_b[i] =
      ((255 - Gamma_Lut.gamma_b[i]) * Gamma_Lut.gamma_b[solarize_reflection_point] /
       (255 - Gamma_Lut.gamma_b[solarize_reflection_point]));
  }
} /* vfe_gamma_get_table */

/** vfe_gamma_set_contrast:
 *    @mod: gamma module instance
 *    @pix_settings: PIX parameters
 *    @in_param_size: parameters size
 *
 *  This function runs in ISP HW thread context.
 *
 *  This function sets gamma table depending on contrast
 *
 *  Return:   0: Success
 *           -1: Parameter size does not match
 **/
static int vfe_gamma_set_contrast(isp_gamma_mod_t *mod,
  isp_hw_pix_setting_params_t *pix_settings, uint32_t in_param_size)
{
  int rc = 0;

  if (in_param_size != sizeof(isp_hw_pix_setting_params_t)) {
    /* size mismatch */
    CDBG_ERROR("%s: size mismatch, expecting = %d, received = %d",
           __func__, sizeof(isp_hw_pix_setting_params_t), in_param_size);

    return -1;
  }

  ISP_DBG(ISP_MOD_GAMMA, "%s: bs_mode %d", __func__, pix_settings->bestshot_mode);
  if (pix_settings->bestshot_mode != CAM_SCENE_MODE_OFF) {
    CDBG_HIGH("%s: Warning Best shot enabled, ignore contast", __func__);

    return 0;
  }

  switch(mod->gamma_table_type) {
  case GAMMA_TABLE_SOLARIZE:
  case GAMMA_TABLE_POSTERIZE:
  case GAMMA_TABLE_BLACK_BOARD:
  case GAMMA_TABLE_WHITE_BOARD:
  case GAMMA_TABLE_BACKLIGHT: {
    CDBG_HIGH("%s: Warning Effect enabled, ignore contast", __func__);

    return 0;
  }
    break;

  default:
    break;
  }

  if (mod->contrast != pix_settings->effects.contrast) {
     ISP_DBG(ISP_MOD_GAMMA, "%s: contrast changed contrast = %d\n", __func__, mod->contrast);
     mod->contrast = pix_settings->effects.contrast;
     mod->hw_update_pending = TRUE;
  }

  ISP_DBG(ISP_MOD_GAMMA, "%s: X, hw_update = %d\n", __func__, mod->hw_update_pending);

  return rc;
} /* vfe_gamma_set_contrast */

/** gamma_set_effect
 *    @mod: gamma module instance
 *    @pix_settings: pix settings
 *    @in_param_size: pix settings size
 *
 *  Set gamma table according required effect.
 **/
static int gamma_set_effect(isp_gamma_mod_t* mod,
  isp_hw_pix_setting_params_t *pix_settings, uint32_t in_param_size)
{
  int rc = 0;
  uint32_t mask;
  chromatix_parms_type *chromatix =
    (chromatix_parms_type *)pix_settings->chromatix_ptrs.chromatixPtr;

  mask = pix_settings->effects.effect_type_mask;

  /* Special effect and contrast are mutually exclusive. Special effect has
     higher priority. Thus when special effect is applied, contrast is not
     applied and set to default */
  if (mask & (1 << ISP_EFFECT_SPECIAL)) {
    rc = gamma_set_spl_effect(mod, pix_settings, in_param_size);
    if(rc)
      goto END;
  }

  if (mask & (1 << ISP_EFFECT_CONTRAST)) {
    rc = vfe_gamma_set_contrast(mod, pix_settings, in_param_size);
    if(rc) {
      goto END;
    }
  }

END:
  return rc;
} /* gamma_set_effect */

/** gamma_reset:
 *    @mod: gamma module instance
 *
 *  This function runs in ISP HW thread context.
 *
 *  This function resets gamma module to a known state
 *
 *  Return:   None
 **/
static void gamma_reset(isp_gamma_mod_t *mod)
{
  mod->old_streaming_mode = CAM_STREAMING_MODE_MAX;
  memset(&mod->ISP_GammaCfgCmd, 0, sizeof(mod->ISP_GammaCfgCmd));
  mod->hw_update_pending = 0;
  mod->trigger_update = 0;
  mod->trigger_enable = 0;
  mod->enable = 0;
  memset(&mod->gamma_table_rgb, 0, sizeof(mod->gamma_table_rgb));
  memset(&mod->solarize_gamma_table, 0, sizeof(mod->solarize_gamma_table));
  memset(&mod->gamma_ratio, 0, sizeof(mod->gamma_ratio));
  mod->gamma_lut_size = 0;
  mod->contrast = 0;
  mod->gamma_table_type = GAMMA_TABLE_DEFAULT;
  mod->backlight_severity = 0;
  mod->enable_backlight_compensation = 0;
  mod->reload_params = 0;
  mod->vfe_reconfig = 0;
}/* gamma_reset */

/** gamma_init:
 *    @mod_ctrl: gamma module instance
 *    @in_params: reset parmeters
 *    @notify_ops: module notification operations
 *
 *  This function runs in ISP HW thread context.
 *
 *  This function initializes gamma module
 *
 *  Return:   None
 **/
static int gamma_init (void *mod_ctrl, void *in_params,
  isp_notify_ops_t *notify_ops)
{
  isp_gamma_mod_t *gamma = mod_ctrl;
  isp_hw_mod_init_params_t *init_params = in_params;

  gamma->fd = init_params->fd;
  gamma->notify_ops = notify_ops;
  gamma->old_streaming_mode = CAM_STREAMING_MODE_MAX;
  gamma_reset(gamma);

  return 0;
}/* gamma_init */

/** gamma_config:
 *    @gamma: gamma module instance
 *    @pix_settings: PIX parameters
 *    @in_param_size: PIX parameters size
 *
 *  This function runs in ISP HW thread context.
 *
 *  This function makes initial configuration of gamma module
 *
 *  Return:   0 - Success
 *           -1 - Parameters size mismatch
 **/
static int gamma_config(isp_gamma_mod_t *gamma,
  isp_hw_pix_setting_params_t *pix_settings, uint32_t in_param_size)
{
  int  rc = 0;
  chromatix_parms_type *chromatix_ptr =
    (chromatix_parms_type *)pix_settings->chromatix_ptrs.chromatixPtr;
  chromatix_gamma_type *pchromatix_gamma =
      &(chromatix_ptr->chromatix_VFE.chromatix_gamma);
  isp_gamma_rgb_t contrast_gamma_table_rgb;

  if (in_param_size != sizeof(isp_hw_pix_setting_params_t)) {
    /* size mismatch */
    CDBG_ERROR("%s: size mismatch, expecting = %d, received = %d",
         __func__, sizeof(isp_hw_pix_setting_params_t), in_param_size);

    return -1;
  }

  /*init gamma parameters*/
  gamma->contrast = pix_settings->effects.contrast;
  gamma->gamma_table_type = GAMMA_TABLE_DEFAULT;
  gamma->enable_backlight_compensation = TRUE;

  /*load chromatix to gamma*/
  chromatix_to_isp_gamma(&(gamma->gamma_table_rgb),
    &(pchromatix_gamma->default_gamma_table));
  gamma->gamma_lut_size = GAMMA40_CHROMATIX_LUT_SIZE;

  chromatix_to_isp_gamma(&gamma->default_gamma_tbl, &pchromatix_gamma->default_gamma_table);
  chromatix_to_isp_gamma(&gamma->lowlight_gamma_tbl, &pchromatix_gamma->lowlight_gamma_table);
  chromatix_to_isp_gamma(&gamma->outdoor_gamma_tbl, &pchromatix_gamma->outdoor_gamma_table);

  gamma_set_solarize_table(gamma, chromatix_ptr);

  if (pix_settings->bestshot_mode == CAM_SCENE_MODE_OFF) {
    /* compensate for contrast */
    switch(gamma->gamma_table_type) {
      case GAMMA_TABLE_SOLARIZE:
      case GAMMA_TABLE_POSTERIZE:
      case GAMMA_TABLE_BACKLIGHT:
      case GAMMA_TABLE_WHITE_BOARD:
      case GAMMA_TABLE_BLACK_BOARD:
        /* special effect, no contrast apply.
           config gamma HW table and configuration*/
        gamma_update_vfe_table(&gamma->ISP_GammaCfgCmd, &(gamma->gamma_table_rgb),
          gamma->gamma_lut_size);
        break;
      default:
        /* apply contrast, update the original table*/
        if (gamma->contrast != DEFAULT_CONTRAST) {
          gamma_update_tab_on_contrast(gamma->contrast,
            gamma->gamma_lut_size, &(gamma->gamma_table_rgb),
            &contrast_gamma_table_rgb);
          gamma_update_vfe_table(&gamma->ISP_GammaCfgCmd, &(contrast_gamma_table_rgb),
            gamma->gamma_lut_size);
        } else {
          /* contrast 5, defaul table, use original table*/
          gamma_update_vfe_table(&gamma->ISP_GammaCfgCmd, &(gamma->gamma_table_rgb),
            gamma->gamma_lut_size);
        }
        break;
    }
  } else {
    gamma_update_vfe_table(&gamma->ISP_GammaCfgCmd, &(gamma->gamma_table_rgb),
      gamma->gamma_lut_size);
  }

  /*config gamma HW table and configuration*/
  gamma->ISP_GammaCfgCmd.LutSel.ch0BankSelect = 0;
  gamma->ISP_GammaCfgCmd.LutSel.ch1BankSelect = 0;
  gamma->ISP_GammaCfgCmd.LutSel.ch2BankSelect = 0;

  gamma->hw_update_pending = TRUE;
  ISP_DBG(ISP_MOD_GAMMA, "%s: X\n", __func__);

  return rc;
} /* gamma_config */

/** gamma_enable:
 *    @gamma: gamma module instance
 *    @enable: true if module is to be enabled
 *    @in_param_size: enable parameter size
 *
 *  This function runs in ISP HW thread context.
 *
 *  This function enables gamma module
 *
 *  Return:   0 - Success
 *           -1 - Parameters size mismatch
 **/
static int gamma_enable(isp_gamma_mod_t *gamma,
                isp_mod_set_enable_t *enable,
                uint32_t in_param_size)
{
  if (in_param_size != sizeof(isp_mod_set_enable_t)) {
    /* size mismatch */
    CDBG_ERROR("%s: size mismatch, expecting = %d, received = %d",
           __func__, sizeof(isp_mod_set_enable_t), in_param_size);

    return -1;
  }
  gamma->enable = enable->enable;

  return 0;
}

/** gamma_trigger_enable:
 *    @gamma: gamma module instance
 *    @enable: true if triger update is enabled
 *    @in_param_size: enable parameter size
 *
 *  This function runs in ISP HW thread context.
 *
 *  This function enables triger update of gamma module
 *
 *  Return:   0 - Success
 *           -1 - Parameters size mismatch
 **/
static int gamma_trigger_enable(isp_gamma_mod_t *gamma,
                isp_mod_set_enable_t *enable,
                uint32_t in_param_size)
{
  if (in_param_size != sizeof(isp_mod_set_enable_t)) {
    /* size mismatch */
    CDBG_ERROR("%s: size mismatch, expecting = %d, received = %d",
           __func__, sizeof(isp_mod_set_enable_t), in_param_size);

    return -1;
  }

  gamma->trigger_enable = enable->enable;

  return 0;
} /* gamma_trigger_enable */

/** gamma_destroy:
 *    @mod_ctrl: gamma module instance
 *
 *  This function runs in ISP HW thread context.
 *
 *  This function destroys gamma module
 *
 *  Return:   0 - Success
 **/
static int gamma_destroy (void *mod_ctrl)
{
  isp_gamma_mod_t *gamma = mod_ctrl;

  memset(gamma,  0,  sizeof(isp_gamma_mod_t));
  free(gamma);

  return 0;
} /* gamma_destroy */

/** gamma_set_params:
 *    @mod_ctrl: gamma module instance
 *    @param_id: parameter id
 *    @in_params: parameter data
 *    @in_param_size: parameter size
 *
 *  This function runs in ISP HW thread context.
 *
 *  This function sets a parameter to gamma module
 *
 *  Return:   0 - Success
 *            Negative - paramter set error
 **/
static int gamma_set_params (void *mod_ctrl, uint32_t param_id,
                     void *in_params, uint32_t in_param_size)
{
  isp_gamma_mod_t *gamma = mod_ctrl;
  int rc = 0;
  ISP_DBG(ISP_MOD_GAMMA, "%s: param id = %d\n", __func__, param_id);

  switch (param_id) {
  case ISP_HW_MOD_SET_MOD_ENABLE:
    rc = gamma_enable(gamma, (isp_mod_set_enable_t *)in_params,
                     in_param_size);
    break;

  case ISP_HW_MOD_SET_MOD_CONFIG:
    rc = gamma_config(gamma, in_params, in_param_size);
    break;

  case ISP_HW_MOD_SET_TRIGGER_ENABLE:
    rc = gamma_trigger_enable(gamma, in_params, in_param_size);
    break;

  case ISP_HW_MOD_SET_TRIGGER_UPDATE:
    rc = gamma_trigger_update(gamma,
      (isp_pix_trigger_update_input_t *)in_params, in_param_size);
    break;

  case ISP_HW_MOD_SET_BESTSHOT:
     rc = gamma_set_bestshot(gamma, in_params, in_param_size);
     break;

  case ISP_HW_MOD_SET_EFFECT:
     rc = gamma_set_effect(gamma, in_params, in_param_size);
     break;

  default:
    CDBG_ERROR("%s: param_id is not supported in this module\n", __func__);
    break;
  }

  return rc;
} /* gamma_set_params */

/** gamma_get_params:
 *    @mod_ctrl: gamma module instance
 *    @param_id: parameter id
 *    @in_params: input parameter data
 *    @in_param_size: input parameter size
 *    @out_params: output parameter data
 *    @out_param_size: output parameter size
 *
 *  This function runs in ISP HW thread context.
 *
 *  This function gets a parameter from gamma module
 *
 *  Return:   0 - Success
 *            Negative - paramter get error
 **/
static int gamma_get_params (void *mod_ctrl, uint32_t param_id,
                     void *in_params, uint32_t in_param_size,
                     void *out_params, uint32_t out_param_size)
{
  isp_gamma_mod_t *gamma = mod_ctrl;
  int rc =0;

  switch (param_id) {
  case ISP_HW_MOD_GET_MOD_ENABLE: {
    isp_mod_get_enable_t *enable = out_params;

    if (sizeof(isp_mod_get_enable_t) != out_param_size) {
      CDBG_ERROR("%s: error, out_param_size mismatch, param_id = %d",
                 __func__, param_id);
      break;
    }

    enable->enable = gamma->enable;
  }
    break;

  case ISP_HW_MOD_GET_TBLS: {
    mct_isp_table_t *isp_tbls = (mct_isp_table_t *)out_params;
    if (sizeof(mct_isp_table_t) != out_param_size) {
      CDBG_ERROR("%s: error, out_param_size mismatch, param_id = %d",
                 __func__, param_id);

      return -1;
    }

    if (gamma->enable && isp_tbls->gamma_table){
      memcpy(isp_tbls->gamma_table, &gamma->ISP_GammaCfgCmd.Gamatbl,
        sizeof(ISP_GammaTable));
      isp_tbls->gamma_num_entries = MAX_GAMMA_TABLE_SIZE;
    }
    break;
  }
  case ISP_HW_MOD_GET_TABLE_SIZE: {
    isp_hw_read_info *read_info = out_params;

    read_info->read_type = VFE_READ_DMI_16BIT;
    read_info->read_bank = RGBLUT_RAM_CH0_BANK0;
    read_info->bank_idx = 0;

    read_info->read_lengh =  sizeof(int16_t) * ISP_GAMMA_NUM_ENTRIES;
  }
    break;
  case ISP_HW_MOD_GET_DMI_DUMP_USER: {
    isp_hw_read_info *read_info = in_params;
    uint32_t *dmi_dump = (uint32_t *) out_params;

    memcpy(out_params, &gamma->applied_table, read_info->read_lengh);
  }
     break;

  case ISP_HW_MOD_GET_VFE_DIAG_INFO_USER: {
    vfe_diagnostics_t *vfe_diag = (vfe_diagnostics_t *)out_params;
    if (sizeof(vfe_diagnostics_t) != out_param_size) {
      CDBG_ERROR("%s: error, out_param_size mismatch, param_id = %d",
        __func__, param_id);
      break;
    }
    vfe_diag->control_gamma.enable = gamma->enable;
    vfe_diag->control_gamma.cntrlenable = gamma->trigger_enable;
    /*Populate vfe_diag data*/
    ISP_DBG(ISP_MOD_GAMMA, "%s: Populating vfe_diag data", __func__);
  }
    break;

  default:
    rc = -EPERM;
    break;
  }

  return rc;
}

/** gamma_get_params:
 *    @mod_ctrl: gamma module instance
 *    @gamma_channel: parameter id
 *
 *  This function runs in ISP HW thread context.
 *
 *  TODO
 *
 *  Return:   0 - Success
 **/
static int gamma_reset_dmi_cfg(isp_gamma_mod_t *gamma_mod,
  uint32_t gamma_channel)
{
  int i, rc = 0;
  struct msm_vfe_cfg_cmd2 cfg_cmd;
  struct msm_vfe_reg_cfg_cmd reg_cfg_cmd[2];
  uint32_t dmi_cfg[2];

  /* reset dmi cfg: config dmi channel and set auto increment*/
  dmi_cfg[0] = ISP40_DMI_CFG_DEFAULT;
  dmi_cfg[0] += gamma_channel;

  /* reset dmi_addr_cfg: dmi address always start form 0 */
  dmi_cfg[1] = 0;

  /* PACK the 2 cfg cmd for 1 ioctl*/
  cfg_cmd.cfg_data = &dmi_cfg;
  cfg_cmd.cmd_len = sizeof(dmi_cfg);
  cfg_cmd.cfg_cmd = (void *) &reg_cfg_cmd;
  cfg_cmd.num_cfg = 2;

  reg_cfg_cmd[0].u.rw_info.cmd_data_offset = 0;
  reg_cfg_cmd[0].cmd_type = VFE_WRITE_MB;
  reg_cfg_cmd[0].u.rw_info.reg_offset = ISP40_DMI_CFG_OFF;
  reg_cfg_cmd[0].u.rw_info.len = 1 * sizeof(uint32_t);

  reg_cfg_cmd[1].u.rw_info.cmd_data_offset =
    reg_cfg_cmd[0].u.rw_info.cmd_data_offset +
      reg_cfg_cmd[0].u.rw_info.len;
  reg_cfg_cmd[1].cmd_type = VFE_WRITE_MB;
  reg_cfg_cmd[1].u.rw_info.reg_offset = ISP40_DMI_ADDR;
  reg_cfg_cmd[1].u.rw_info.len = 1 * sizeof(uint32_t);

  rc = ioctl(gamma_mod->fd, VIDIOC_MSM_VFE_REG_CFG, &cfg_cmd);
  if (rc < 0){
    CDBG_ERROR("%s: gamma DMI update error, rc = %d", __func__, rc);

    return rc;
  }

  return rc;
} /* gamma_reset_dmi_cfg */

/** gamma_single_HW_write:
 *    @fd: device fd
 *    @cmd_offset:command
 *    @cmd_len: command length
 *    @hw_reg_offset: HW register offset
 *    @reg_num: number of registers
 *    @cmd_type: type of command
 *
 *  This function runs in ISP HW thread context.
 *
 *  This function performs single HW write.
 *
 *  Return:   0 - Success
 **/
static int gamma_single_HW_write(uint32_t fd, void* cmd_offset,
  uint32_t cmd_len, uint32_t hw_reg_offset, uint32_t reg_num, uint32_t cmd_type)
{

  int rc = 0;
  struct msm_vfe_cfg_cmd2 cfg_cmd;
  struct msm_vfe_reg_cfg_cmd reg_cfg_cmd[1];

  cfg_cmd.cfg_data = cmd_offset;
  cfg_cmd.cmd_len = cmd_len;
  cfg_cmd.cfg_cmd = (void *) reg_cfg_cmd;
  cfg_cmd.num_cfg = 1;

  reg_cfg_cmd[0].u.rw_info.cmd_data_offset = 0;
  reg_cfg_cmd[0].cmd_type = cmd_type;
  reg_cfg_cmd[0].u.rw_info.reg_offset = hw_reg_offset;
  reg_cfg_cmd[0].u.rw_info.len = reg_num * sizeof(uint32_t);

  reg_cfg_cmd[0].u.dmi_info.hi_tbl_offset = 0;
  reg_cfg_cmd[0].u.dmi_info.lo_tbl_offset = 0;

  reg_cfg_cmd[0].u.dmi_info.hi_tbl_offset = 0;
  reg_cfg_cmd[0].u.dmi_info.lo_tbl_offset = 0;
  reg_cfg_cmd[0].u.dmi_info.len = cmd_len;

  rc = ioctl(fd, VIDIOC_MSM_VFE_REG_CFG, &cfg_cmd);
  if (rc < 0){
    CDBG_ERROR("%s: HW update error, rc = %d", __func__, rc);

    return rc;
  }

  return rc;

} /* gamma_single_HW_write */

/** gamma_dmi_hw_update:
 *    @gamma_mod:
 *    @bank_sel:
 *
 *  This function runs in ISP HW thread context.
 *
 *  TODO
 *
 *  Return:   0 - Success
 **/
static int gamma_dmi_hw_update(isp_gamma_mod_t *gamma_mod,
  ISP_GammaLutSelect bank_sel)
{
  int rc = 0;
  uint32_t dmi_cfg;
  uint32_t dmi_addr_reset = 0;

  int16_t *tbl_r = &gamma_mod->ISP_GammaCfgCmd.Gamatbl.hw_table_r[0];
  int16_t *tbl_g = &gamma_mod->ISP_GammaCfgCmd.Gamatbl.hw_table_g[0];
  int16_t *tbl_b = &gamma_mod->ISP_GammaCfgCmd.Gamatbl.hw_table_b[0];
  uint32_t tbl_len = sizeof(int16_t) * ISP_GAMMA_NUM_ENTRIES;

  uint32_t gamma_channel_0 =
    (bank_sel.ch0BankSelect == 0)? RGBLUT_RAM_CH0_BANK0 : RGBLUT_RAM_CH0_BANK1;
  uint32_t gamma_channel_1 =
    (bank_sel.ch1BankSelect == 0)? RGBLUT_RAM_CH1_BANK0 : RGBLUT_RAM_CH1_BANK1;
  uint32_t gamma_channel_2 =
    (bank_sel.ch2BankSelect == 0)? RGBLUT_RAM_CH2_BANK0 : RGBLUT_RAM_CH2_BANK1;

  /* 1. program DMI default value, write auto increment bit
     2. write DMI table
     3. reset DMI cfg
     4. flip the banksel bit*/

  /* write gamma channel 0 */
  gamma_reset_dmi_cfg(gamma_mod, gamma_channel_0);

  rc = gamma_single_HW_write(gamma_mod->fd, (void *)tbl_g, tbl_len,
    ISP40_DMI_DATA_LO, 1, VFE_WRITE_DMI_16BIT);

  if(rc < 0)
    gamma_reset_dmi_cfg(gamma_mod, ISP40_DMI_NO_MEM_SELECTED);

  /* write gamma channel 1 */
  gamma_reset_dmi_cfg(gamma_mod, gamma_channel_1);

  rc = gamma_single_HW_write(gamma_mod->fd, (void *)tbl_b, tbl_len,
    ISP40_DMI_DATA_LO, 1, VFE_WRITE_DMI_16BIT);

  if(rc < 0)
    gamma_reset_dmi_cfg(gamma_mod, ISP40_DMI_NO_MEM_SELECTED);

  /* write gamma channel 2 */
  gamma_reset_dmi_cfg(gamma_mod, gamma_channel_2);

  gamma_single_HW_write(gamma_mod->fd, (void *)tbl_r, tbl_len,
    ISP40_DMI_DATA_LO, 1, VFE_WRITE_DMI_16BIT);

  gamma_reset_dmi_cfg(gamma_mod, ISP40_DMI_NO_MEM_SELECTED);

  return rc;
} /* gamma_dmi_hw_update */

/** gamma_do_hw_update:
 *    @gamma_mod: gamma module instance
 *
 *  This function runs in ISP HW thread context.
 *
 *  This function checks and sends configuration update to kernel
 *
 *  Return:   0 - Success
 *           -1 - configuration error
 **/
static int gamma_do_hw_update(isp_gamma_mod_t *gamma_mod)
{
  int i, rc = 0;
  ISP_DBG(ISP_MOD_GAMMA, "%s: hw_pending = %d\n", __func__, gamma_mod->hw_update_pending);
  if (gamma_mod->hw_update_pending) {

    gamma_dmi_hw_update(gamma_mod,
      gamma_mod->ISP_GammaCfgCmd.LutSel);

    isp_pipeline_util_single_HW_write(gamma_mod->fd,
    &gamma_mod->ISP_GammaCfgCmd, sizeof(gamma_mod->ISP_GammaCfgCmd.LutSel),
    ISP_RGB_LUT40_OFF, ISP_RGB_LUT40_LEN, VFE_WRITE);

    gamma_mod->ISP_GammaCfgCmd.LutSel.ch0BankSelect ^= 1;
    gamma_mod->ISP_GammaCfgCmd.LutSel.ch1BankSelect ^= 1;
    gamma_mod->ISP_GammaCfgCmd.LutSel.ch2BankSelect ^= 1;

    gamma_mod->applied_table = gamma_mod->ISP_GammaCfgCmd.Gamatbl;
    gamma_mod->hw_update_pending = 0;
  }

  return rc;
}/* gamma_do_hw_update */

/** gamma_action:
 *    @mod_ctrl: gamma module instance
 *    @action_code: action id
 *    @data: input parameter data
 *    @data_size: input parameter size
 *
 *  This function runs in ISP HW thread context.
 *
 *  This function executes an gamma module action
 *
 *  Return:   0 - Success
 *            Negative - action execution error
 **/
static int gamma_action (void *mod_ctrl, uint32_t action_code, void *data,
  uint32_t data_size)
{
  int rc = 0;
  isp_gamma_mod_t *gamma = mod_ctrl;

  switch (action_code) {
  case ISP_HW_MOD_ACTION_HW_UPDATE:
    rc = gamma_do_hw_update(gamma);
    break;

  case ISP_HW_MOD_ACTION_RESET:
    gamma_reset(gamma);
    break;

  default:
    /* no op */
    rc = -EAGAIN;
    CDBG_HIGH("%s: action code = %d is not supported. nop",
              __func__, action_code);
    break;
  }

  return rc;
} /* gamma_action */

/** gamma40_open:
 *    @version: version
 *
 *  This function runs in ISP HW thread context.
 *
 *  This function instantiates a gamma module
 *
 *  Return:   NULL - not enough memory
 *            Otherwise handle to module instance
 **/
isp_ops_t *gamma40_open(uint32_t version)
{
  isp_gamma_mod_t *gamma = malloc(sizeof(isp_gamma_mod_t));

  if (!gamma) {
    /* no memory */
    CDBG_ERROR("%s: no mem",  __func__);

    return NULL;
  }
  memset(gamma,  0,  sizeof(isp_gamma_mod_t));
  gamma->ops.ctrl = (void *)gamma;
  gamma->ops.init = gamma_init;
  /* destroy the module object */
  gamma->ops.destroy = gamma_destroy;
  /* set parameter */
  gamma->ops.set_params = gamma_set_params;
  /* get parameter */
  gamma->ops.get_params = gamma_get_params;
  gamma->ops.action = gamma_action;

  return &gamma->ops;
} /* gamma40_open */
